--!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
-- CUSTOM CONFIG EXAMPLE -- SOL 2.0 and later



-- This is just an example, how custom sol config could be used
-- This file must have the same name like your PPFilter and the extension lua

-- For your release version, this file should be placed in the folder /system/cfg/ppfilters/sol_custom_configs/
-- For realtime editing, you can place it in /extension/weather/sol as well.


-- using a LUT (Look Up Table) has some advantages for controlling things - You can do nonlinear changes...
-- define a LUT:

-- a LUT with custom index
n = 1                  
local _l_LUT_custom = {}
		      --    index  a     b     c
_l_LUT_custom[n] = {    0, 1.00, 1.00, 1.00 } n=n+1
_l_LUT_custom[n] = {    1, 3.00, 1.00, 1.00 } n=n+1
_l_LUT_custom[n] = {    2, 5.00, 1.00, 1.00 } n=n+1
_l_LUT_custom[n] = {    3, 7.00, 1.00, 1.00 } n=n+1
_l_LUT_custom[n] = {    4, 6.00, 1.00, 1.00 } n=n+1
_l_LUT_custom[n] = {    5, 5.00, 1.00, 1.00 } n=n+1
_l_LUT_custom[n] = {    6, 4.00, 1.00, 1.00 } n=n+1
_l_LUT_custom[n] = {    7, 2.00, 1.00, 1.00 } n=n+1
_l_LUT_custom[n] = {    8, 0.00, 1.00, 1.00 } n=n+1
_l_LUT_custom[n] = {    9,-1.00, 1.00, 1.00 } n=n+1
_l_LUT_custom[n] = {   10,-5.00, 1.00, 1.00 } n=n+1

-- a LUT for sunangle dependency
-- please define the whole span [-90°..90°]
n = 1                  
local _l_LUT_sunangle = {}
		   --    index=sunangle  a     b     c
_l_LUT_sunangle[n] = {      -90, 1.00, 1.00, 1.00 } n=n+1
_l_LUT_sunangle[n] = {      -20, 3.00, 1.00, 1.00 } n=n+1
_l_LUT_sunangle[n] = {      -15, 5.00, 1.00, 1.00 } n=n+1
_l_LUT_sunangle[n] = {       -5, 7.00, 1.00, 1.00 } n=n+1
_l_LUT_sunangle[n] = {       -2, 6.00, 1.00, 1.00 } n=n+1
_l_LUT_sunangle[n] = {        0, 5.00, 1.00, 1.00 } n=n+1
_l_LUT_sunangle[n] = {        5, 4.00, 1.00, 1.00 } n=n+1
_l_LUT_sunangle[n] = {       15, 2.00, 1.00, 1.00 } n=n+1
_l_LUT_sunangle[n] = {       30, 0.00, 1.00, 1.00 } n=n+1
_l_LUT_sunangle[n] = {       45,-1.00, 1.00, 1.00 } n=n+1
_l_LUT_sunangle[n] = {       90,-5.00, 1.00, 1.00 } n=n+1

-- a LUT with Colors
-- You need to use HSV format
n = 1                  
local _l_LUT_custom_color = {}
		            --    index  H    S     V
_l_LUT_custom_color[n] = {    0, 220, 0.50, 1.00 } n=n+1
_l_LUT_custom_color[n] = {    1, 210, 0.70, 1.00 } n=n+1
_l_LUT_custom_color[n] = {    2, 200, 0.80, 1.00 } n=n+1
_l_LUT_custom_color[n] = {    3, 180, 0.90, 1.00 } n=n+1
_l_LUT_custom_color[n] = {    4, 170, 1.00, 1.00 } n=n+1
_l_LUT_custom_color[n] = {    5, 200, 0.90, 1.00 } n=n+1
_l_LUT_custom_color[n] = {    6, 220, 0.80, 1.00 } n=n+1
_l_LUT_custom_color[n] = {    7, 240, 0.70, 1.00 } n=n+1
_l_LUT_custom_color[n] = {    8, 260, 0.60, 1.00 } n=n+1
_l_LUT_custom_color[n] = {    9, 280, 0.50, 1.00 } n=n+1
_l_LUT_custom_color[n] = {   10, 300, 0.40, 1.00 } n=n+1



function sol_custom_weather_definitions()

	-- The weather definitions is my very own system of configuring the weather
	-- It is not developed to easily customize it. So change them at your own risk.
	-- Also with further development, many things can change here.
	-- So its better to do very little changes, to adapt them to your needs.

	--[[
	local id

	-- this is the weather classification from Content Manager
	id = 1  -- LightThunderstorm
	id = 2  -- Thunderstorm
	id = 3  -- HeavyThunderstorm
	id = 4  -- LightDrizzle
	id = 5  -- Drizzle
	id = 6  -- HeavyDrizzle
	id = 7  -- LightRain
	id = 8  -- Rain
	id = 9  -- HeavyRain
	id = 10 -- LightSnow
	id = 11 -- Snow
	id = 12 -- HeavySnow
	id = 13 -- LightSleet
	id = 14 -- Sleet
	id = 15 -- HeavySleet
	id = 16 -- Clear
	id = 17 -- FewClouds
	id = 18 -- ScatteredClouds
	id = 19 -- BrokenClouds
	id = 20 -- OvercastClouds
	id = 21 -- Fog
	id = 22 -- Mist
	id = 23 -- Smoke
	id = 24 -- Haze
	id = 25 -- Sand
	id = 26 -- Dust
	id = 27 -- Squalls
	id = 28 -- Tornado
	id = 29 -- Hurricane
	id = 32 -- Windy
	id = 33 -- Hail

	--You can define the complete weather - You will find all weather definitions in \extension\weather\sol\sol__weather_definitions.lua

	id = 3 -- HeavyThunderstorm
	-- do not reset this variable
	--__weather_defs[id] = {}
	-- just the name of the weather / don't change this.
	--__weather_defs[id]["name"] = "Heavy Thunderstorm"

	-- !!! The whole sky part is actually in development, much changes will come later
	-- initialize the sky 
	__weather_defs[id]["sky"]    = {} i=1
	-- add a layer ("Cumulus", "Stratus", "Cirrostratus", "DistantHaze", "Lightning")
	-- Notice! Changing the composition of the sky has influence on fps!
	__weather_defs[id]["sky"][i] = { layer="Cumulus", dense=0.9, waterfilled=0.8 } i=i+1
	__weather_defs[id]["sky"][i] = { layer="Lightning", dense=0.9 } i=i+1

	-- this defines a "material" in the sky, use the granulation to clear the horizont 
	__weather_defs[id]["inair_material"]  = { color=hsv(210, 0.6, 0.50), dense=0.15, granulation = 0.05 }

	-- fog modulator
	__weather_defs[id]["fog_dense"] = 0.05

	-- use the humidity modulator to make the horizont more dense
	__weather_defs[id]["humidity"]  = 0.50

	-- the overcat modulator helps to fake a dense cloud cover
	__weather_defs[id]["overcast"]  = 0.6

	-- maybe obsolete soon
	__weather_defs[id]["water_on_road"] = 0.50
	__weather_defs[id]["rain"] = 0.80

	-- this is a helper variable. It tells the core to compensate/boost values to achieve bad weather look
	__weather_defs[id]["badness"] = 1.00


	id = 18 -- ScatteredClouds
	__weather_defs[id]["name"] = "Scattered Clouds"
	__weather_defs[id]["sky"]    = {} i=1
	__weather_defs[id]["sky"][i] = { layer="Cumulus", dense=0.3, waterfilled=0.4 } i=i+1
	__weather_defs[id]["sky"][i] = { layer="Stratus", dense=0.7, waterfilled=0.15 } i=i+1
	__weather_defs[id]["sky"][i] = { layer="Cirrostratus", dense=0.3, waterfilled=0.0 } i=i+1
	__weather_defs[id]["sky"][i] = { layer="DistantHaze", dense=0.2, waterfilled=0.0 } i=i+1
	__weather_defs[id]["inair_material"]  = { color=hsv(210, 0.8, 1.00), dense=0.02, granulation = 0.7 }
	__weather_defs[id]["fog_dense"] = 0.01
	__weather_defs[id]["humidity"]  = 0.50
	__weather_defs[id]["overcast"]  = 0.25
	__weather_defs[id]["water_on_road"] = 0.00
	__weather_defs[id]["rain"] = 0.0
	__weather_defs[id]["badness"] = 0.00


	-- Or just change single elements:
	id = 18 -- ScatteredClouds
	__weather_defs[id]["fog_dense"] = 0.10
	__weather_defs[id]["overcast"]  = 0.10
	


	]]
end

--#######################################################################
--# a little script, to manage your own exposure fixes for tracks
local _l_Exposure_Fixes = {
	{ track = "ks_red_bull_ring", exp_fix = 1.0 },
	{ track = "ks_laguna_seca", exp_fix = 0.8 },
	{ track = "acu_barcelona%-city", exp_fix = 1.0 },
}
function set_track_exposure_fix()

	local trackID = ac.getTrackId()
	local exp_fix = 1.0

	for k, v in pairs(_l_Exposure_Fixes) do
		if string.find(trackID, v.track) == 1 then
			exp_fix = v.exp_fix
			break
		end
	end
	
	ta_exp_fix = exp_fix
end
--#######################################################################



function init_sol_custom_config()

	-- uncomment this for using exposure fix script
	--set_track_exposure_fix()





	-- This will be called once at the start of a session, directly after calling Sol's config
	-- Just copy the values from Sol's config you want to change with the use of your PPFilter and put it here - like:
	SOL__set_config("night", "moonlight_multiplier", 3)



	-- Autoexposure
	-- Since CSP 1.69 a much better AE is possible, because the car's exposure multipliers can be deactivated
	-- So don't use self calibrating AE, use the YEBIS AE
	SOL__set_config("ae", "use_self_calibrating", false)
	-- But neutralise it, to have custom access...
	SOL__set_config("ae", "alternate_ae_mode", 1)

	-- deactivate cars exposure multiplier
	ac.setCarExposureActive(false)

	

	--!!! if you want to use custom sky preset, set sky_preset = 8 !!!
	SOL__set_config("sky", "blue_preset", 8)

	--!!! if you want to use custom distant fog, activate it !!!
	SOL__set_config("nerd__fog_custom_distant_fog", "use", true)


	--# add a weather specific variable with a name and a default value which is defined for all weather with this call
	cc__add_weather_variable("XYZ", 1)

	--# make differences to some special weather
	cc__set_weather_variable("XYZ", "Windy", 2)
	cc__set_weather_variable("XYZ", "NoClouds", 10)
	cc__set_weather_variable("XYZ", "Fog", 0)



	-- get some Video Settings
	local video_mode = weather__get_Video_Settings("CAMERA", "MODE")
	if video_mode then

		if video_mode == "DEFAULT" then

		elseif video_mode == "TRIPLE" then

		elseif video_mode == "OCULUS" then

		elseif video_mode == "OPENVR" then

		end
	end

end

-- this is called not every frame
function update_sol_custom_config(dt)

	-- This will be called every frame
	-- If you want to dynamically change value, do this here.

	-- Please, whatever you do here, do it advisedly. You can mess up everything here. 

	--[[  You can use this weatherFX functions to set PP Filter values:

		ac.setAutoExposureTarget(v)
		ac.setAutoExposureLimits(min, max)
		ac.setGodraysLength(v)
		ac.setGodraysGlareRatio(v)
		ac.setGodraysAngleAttenuation(v)
		ac.setGodraysNoiseFrequency(v)
		ac.setGodraysNoiseMask(v)
		ac.setGodraysDepthMapThreshold(v)
		ac.setGlareThreshold(v)
		ac.setGlareBloomFilterThreshold(v)
		ac.setGlareStarFilterThreshold(v)
		ac.setPpColorTemperatureK(v)
		ac.setPpWhiteBalanceK(v)    
		ac.setPpHue(v)
		ac.setPpSepia(v)
		ac.setPpSaturation(v)
		ac.setPpBrightness(v)
		ac.setPpContrast(v)
		ac.setPpTonemapFunction(int v)
		ac.setPpTonemapExposure(v)
		ac.setPpTonemapGamma(v)
		ac.setPpTonemapMappingFactor(v)
		ac.setPpTonemapFilmicContrast(v)
	]]

	--[[ Using weatherFX's color corrections

		local filter = ac.ColorCorrectionGrayscale {  }
		local filter = ac.ColorCorrectionNegative {  }

		local filter = ac.ColorCorrectionSepiaTone { value = 0 }
		local filter = ac.ColorCorrectionBrightness { value = 0 }
		local filter = ac.ColorCorrectionSaturation { value = 0 }
		local filter = ac.ColorCorrectionContrast { value = 0 }
		local filter = ac.ColorCorrectionBias { value = 0 }

		local filter = ac.ColorCorrectionModulationRgb { color = rgb(1,1,1) }
		local filter = ac.ColorCorrectionSaturationRgb { color = rgb(1,1,1) }
		local filter = ac.ColorCorrectionContrastRgb { color = rgb(1,1,1) }
		local filter = ac.ColorCorrectionBiasRgb { color = rgb(1,1,1) }

		local filter = ac.ColorCorrectionMonotoneRgb { color = rgb(1,1,1), effectRation = 0 }
		local filter = ac.ColorCorrectionMonotoneRgbSatMod { color = rgb(1,1,1), saturation = 0, modulation = 0 }
		local filter = ac.ColorCorrectionFadeRgb { color = rgb(1,1,1), effectRation = 0 }
		local filter = ac.ColorCorrectionHue { hue = 0, keepLuminance = 0 }
		local filter = ac.ColorCorrectionHue { hue = 0, saturation = 0, brightness = 1 }

		local filter = ac.ColorCorrectionTemperature { temperature = 6500, luminance = 0 }
		local filter = ac.ColorCorrectionWhiteBalance { temperature = 6500, luminance = 0 }

		ac.weatherColorCorrections[#ac.weatherColorCorrections + 1] = filter


		Example:
			
			At beginning of custom config:

			local filter_bias = ac.ColorCorrectionBiasRgb { color = rgb(1,1,1) }
			ac.weatherColorCorrections[#ac.weatherColorCorrections + 1] = filter_bias

			local color_bias_low = rgb(0.1,0,0)
			local color_bias_high = rgb(0,0,0.1)


			In update_sol_custom_config():

			filter_bias.color = math.lerp(color_bias_low, color_bias_high, from_twilight_compensate(0))
	]]


	--##############################################################################################
	--[[  This are some functions, to create dependencies to the sunangle
		
		The compensate function returning the given value or 1 (its mainly used as an multiplicator)

		- transition between v and 1 is with sunangles between -6° and -12°
		day_compensate(v)   - returns 1 while day | v while night
		night_compensate(v) - returns 1 while night | v while day

		- transition between v and 1 is with sunangles between +3° and -6°
		from_twilight_compensate(v)  - returns 1 while day | v while night

		- transition between v and 1 is with sunangles between +6° and 0°
		sun_compensate(v)   - returns 1 with sun | v when sun is < 0°

		- transition between v and 1 is with sunangles between +10° and -11°
		duskdawn_compensate(v)  - returns 1 while dusk or dawn
		
		- transition between v and 1 is with sunangles between +30°->+10° and -9°->-20°
		dawn_exclusive(v) 	- returns 1 while not in dawn
		dusk_exclusive(v) 	- returns 1 while not in dusk

		- __IntD(x, y, e) - "Interpolate Day" 
		sin function of the sun angle, to interpolate between:
		x (value when sunangle is 0°) and y (value when sun is 90°)
		e is the exponent of the sin function a = sin(sunangle)^e
		For example __IntD(0, 1, 0.5), will return almost 1 till the sun is realy near the horizon


		E.g.
		"Boost PP Brightness in the night"

		1. Method:
		ac.setPpBrightness( 1.14 * day_compensate(1.1) )

		Brightness will then be 1.14 at day and 1.24 at night


		2. Method (using math.lerp):
		ac.setPpBrightness( math.lerp( 1.24, 1.14, day_compensate(0) ) )
	]]

	--##############################################################################################
	--[[  You can request the main weather modulators / effects
		weather__get_fog_dense()
		weather__get_humidity()
		weather__get_overcast() 
		weather__get_badness()
		weather__get_AE()
		weather__get_cloud_shadow()
		weather__get_cloud_density()
		weather__get_ambient_brightness()

		weather__get_rainIntensity()
		weather__get_rainWetness()
		weather__get_rainPuddles()

		E.g.
		"Boost PP Brightness with bad weather"

		1. Method (using math.lerp):
		ac.setPpBrightness( math.lerp( 1.0, 1.2, weather__get_badness() ) )
	]]


	--[[ Sol Filter functions
		
		--returns Sol's CSP global lights multiplier
		SOL_filter__get_CSP_light_control()

		--returns Sol's special AE exposure base
		SOL_filter__get_exposure_base()
		
		--sets Sol's special AE exposure base
		SOL_filter__set_exposure_base(exposure)
	]]
	

	--[[ Get contents of some inis
		-- get the values of the \assettocorsa\system\cfg\graphics.ini
		weather__get_Graphic_Settings(key, parameter)

		-- get the values of the \Documents\Assetto Corsa\cfg\video.ini
		weather__get_Video_Settings(key, parameter)
	]]


	--##############################################################################################
	--# get a weather specific variable 
	--# it is correctly interpolated while weather transitions
	local xyz = cc__get_weather_variable("XYZ")




	--##############################################################################################
	--  Custom Sky Preset
	--	use the custom sky preset variables and modulate them, e.g. with sunangle functions:

	SOL__custom_sky_preset.hue = 0
	SOL__custom_sky_preset.saturation = 1
	SOL__custom_sky_preset.level = 1
	SOL__custom_sky_preset.atmosphere_color = hsv(30+15*sun_compensate(0),
												  1.0-0.2*sun_compensate(0),
												  __IntD(-0.2, 1.5, 0.5)):toRgb()
											*day_compensate(0)
	SOL__custom_sky_preset.booster = sun_compensate(0.5) -- 1 while day / 0.5 with sunset
	SOL__custom_sky_preset.cloud_adaption = 1
	SOL__custom_sky_preset.cloud_opacity = night_compensate(0.8) -- 0.8 while day / 1.0 for night
	SOL__custom_sky_preset.cloud_level = 1
	SOL__custom_sky_preset.cloud_saturation = 1
	SOL__custom_sky_preset.cloud_saturation_limit = 1


	-- example of setting custom distant fog
	SOL__set_config("nerd__fog_custom_distant_fog", "distance"	, 30000)
	SOL__set_config("nerd__fog_custom_distant_fog", "blend"		, 0.85)
	SOL__set_config("nerd__fog_custom_distant_fog", "density"	, 1.75)
	SOL__set_config("nerd__fog_custom_distant_fog", "exponent"	, 0.75)
	SOL__set_config("nerd__fog_custom_distant_fog", "backlit"	, 0.05)
	SOL__set_config("nerd__fog_custom_distant_fog", "sky"		, 0.00)
	SOL__set_config("nerd__fog_custom_distant_fog", "night"		, 0.00)
	SOL__set_config("nerd__fog_custom_distant_fog", "Hue"		, 220)
	SOL__set_config("nerd__fog_custom_distant_fog", "Saturation", 0.50)
	SOL__set_config("nerd__fog_custom_distant_fog", "Level"		, 2.50)
	


	-- You can make different settings for interior and exterior view
	if ac.isInteriorView() == true then 
		--interior

	else
		--exterior

	end



	-- If you want to debug your things, please put it in this condition.
	-- The debug text only appears, if it is activated in sol_config.
	if sol__debug__custom_config == true then

		local test = __IntD(0, 1, 0.5)
		-- This will output the value limited to 2 digits, e.g. "CC: Test 0.45" 
		ac.debug("CC", string.format('Test %.2f', test) )
	end




	--##### LUTs #####

	-- retrieve the interpolated result of the LUT
	local index = 5
	local _l_LUT_custom_r = interpolate__plan(_l_LUT_custom, nil, index)
	-- the function returns an array/table. All values are interpolated
	-- and use it...
	local special1 = _l_LUT_custom_r[1] -- this will retrieve the interpolated (a) value 
	local special2 = _l_LUT_custom_r[2] -- this will retrieve the interpolated (b) value 

	-- you don't need to set an index for sunangle LUTs, its done automatically
	local _l_LUT_sunangle_r = interpolate__plan(_l_LUT_sunangle)
	-- the function returns an array/table. All values are interpolated
	-- and use it...
	local sun1 = _l_LUT_sunangle_r[1] -- this will retrieve the interpolated (a) value 
	local sun2 = _l_LUT_sunangle_r[2] -- this will retrieve the interpolated (b) value 

	-- if a LUT has color informations in it, you need to give the function the position of it
	local index = 5
	-- the second parameter is a table of color positions. Tell the first position of HSV paramters 
	-- If you have multiple HSV parameters, tell it via the table, e.g. { 1, 4, 8 }
	-- So the function will use [1,2,3] for the first HSV, [4,5,6] for the second one and [8,9,10] for the last one. 
	local _l_LUT_custom_color_r = interpolate__plan(_l_LUT_custom_color, { 1 }, index)
	-- the function returns an array/table. All values are interpolated
	-- Colors are correctly mixed !

	-- create a hsv variable with the results of the LUT
	local hsv1 = hsv(_l_LUT_custom_color_r[1],
					 _l_LUT_custom_color_r[2],
					 _l_LUT_custom_color_r[3]) 

	-- the hsv variable consists of 3 members: hsv1.h, hsv1.s, hsv1.v
	
	-- You can do several things with it, like transform it to RGB:
	-- create a rgb variable
	local rgb = hsv1:toRgb()
	-- the rgb variable consists of 3 members: rgb.r, rgb.g, rgb.b

	-- You can also transform RGB to HSV
	hsv1 = rgb:toHsv()

	--then maybe do this with the hsv variable:
	hsv1.s = hsv1.s * sun1 --this will only change saturation

end



-- this is called every frame
function update_sol_custom_config__every_frame(dt)

	-- for AE controlling, its better to check every frame
	local AE = weather__get_AE()


end


function update_sol_custom_config__post(dt)

	--[[
		With this function, you can manipulate the core weatherFX elements after all Sol calculations/weatherFX calls
	]]



	-- a HSV variable (color) has 3 members:
	-- color.h ( Hue (0=red, 60=yellow, 120=green, 180=cyan, 240=blue, 315=magenta) )
	-- color.s ( Saturation )
	-- color.v ( Value )

	local sun = GFX__get_sun_light_HSV()
	local amb = GFX__get_ambient_light_HSV()
	local fog = GFX__get_fog_color_HSV()

	amb.v = amb.v * (1 + 2.0*duskdawn_compensate(0))
	fog.v = fog.v * (1 + 0.5*duskdawn_compensate(0))
	sun.v = sun.v * sun_compensate(2)

	GFX__set_ambient_light_HSV(amb)
	GFX__set_fog_color_HSV(fog)
	GFX__set_sun_light_HSV(sun)
end